package br.mikhas.util.jdbc;

import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.Properties;
import java.util.logging.Logger;

import javax.sql.DataSource;

import br.mikhas.util.Assert;
import br.mikhas.util.StringUtils;

/**
 * Simple JDBC {@link DataSource} implementation
 * 
 * @author Mikhail Domanoski
 * 
 */
public class SimpleDataSource implements DataSource {

	/**
	 * The username to be used to get the connection
	 */
	private String user = "";

	/**
	 * The password to be used when getting a new connection
	 */
	private String password = "";

	private String url;

	/**
	 * The jdbc driver to use
	 */
	private Driver driver;

	/**
	 * Creates a new instance of {@link SimpleDataSource}
	 */
	public SimpleDataSource() {

	}

	/**
	 * Creates a new instance of {@link SimpleDataSource} and defines the used
	 * url.
	 * 
	 * @param url
	 *            The used url
	 */
	public SimpleDataSource(String url) {
		this.setUrl(url);
	}

	/**
	 * Sets the used url
	 * 
	 * @param url
	 *            The url to connect
	 */
	private void setUrl(String url) {
		Assert.notNull(url);
		this.url = url;
	}

	/**
	 * Creates a new instance of {@link SimpleDataSource}, defines the used JDBC
	 * driver and the datasource url.
	 * 
	 * @param url
	 *            The datasource URL to use
	 * @param driver
	 *            The name of the used JDBC driver class
	 */
	public SimpleDataSource(String url, String driver) {
		this.setUrl(url);
		setDriver(driver);
	}

	/**
	 * Sets the used driver class
	 * 
	 * @param driver
	 *            The name of the driver class
	 */
	public void setDriver(String driver) {
		Assert.notEmpty(driver);
		try {
			this.driver = (Driver) Class.forName(driver).newInstance();
		} catch (Throwable e) {
			throw new JdbcException(
					"Could not create driver: "
							+ driver
							+ ". Be sure that the driver class is present in the classpath.");
		}
	}

	/**
	 * Sets the username used to log into the datasource
	 * 
	 * @param username
	 *            The username
	 */
	public void setUsername(String username) {
		this.user = username;
	}

	/**
	 * Sets the password used to log into the datasource
	 * 
	 * @param password
	 *            The password to use
	 */
	public void serPassword(String password) {
		this.password = password;
	}

	@Override
	public Connection getConnection() throws SQLException {
		if (driver != null) {
			return driver.connect(url, getProperties());
		} else {
			if (StringUtils.isEmpty(user))
				return DriverManager.getConnection(this.url);
			else
				return DriverManager.getConnection(url, user, password);
		}
	}

	@Override
	public Connection getConnection(String username, String password)
			throws SQLException {
		return DriverManager.getConnection(url, username, password);
	}

	@Override
	public PrintWriter getLogWriter() throws SQLException {
		return DriverManager.getLogWriter();
	}

	@Override
	public int getLoginTimeout() throws SQLException {
		return DriverManager.getLoginTimeout();
	}

	@Override
	public void setLogWriter(PrintWriter out) throws SQLException {
		DriverManager.setLogWriter(out);
	}

	@Override
	public void setLoginTimeout(int seconds) throws SQLException {
		DriverManager.setLoginTimeout(seconds);
	}

	@Override
	public boolean isWrapperFor(Class<?> iface) throws SQLException {
		return iface == this.getClass();
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T> T unwrap(Class<T> iface) throws SQLException {
		return (T) this;
	}

	private Properties getProperties() {
		Properties prop = new Properties();
		if (this.user != null) {
			prop.setProperty("user", this.user);
			if (this.password != null)
				prop.setProperty("password", this.password);
		}
		return prop;
	}

	@Override
	public Logger getParentLogger() throws SQLFeatureNotSupportedException {
		// TODO Auto-generated method stub
		return null;
	}

}
